#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "linda.h"
#include "tuple.h"


pattern* read_pattern(const char * path, int *pid)
{
    int count, i, len;
    pattern *pat;
    element_of_pattern *first, *cur = NULL, *prev = NULL;
    FILE *input = fopen(path, "rb");
    
    if (input == NULL) {
        printf("Nie udalo sie otworzyc pliku wzorca krotki do odczytu (%s).", path);
        return NULL;
    }
    
    // Odczyt PIDu procesu.
    pid_t x;
    fread(&x, sizeof(pid_t), 1, input);
    if (pid != NULL) *pid = x;
    
    // Odczytanie liczby elementów wzorca krotki.
    fread(&count, sizeof(count), 1, input);
    
    // Alokacja pamięci dla wzorca krotki i odczyt jego struktury.
    pat = malloc(sizeof(pattern));
    fread(pat, sizeof(pattern), 1, input);

    if (count == 0) {
        pat->first = NULL;
        return pat;
    }
    
    first = malloc(sizeof(element_of_pattern));
    
    // Odczyt struktur wzorca krotki.
    for (i = 0; i < count; i++) {
        if (prev != NULL)
            cur = malloc(sizeof(element_of_pattern));
        else
            cur = first;
        
        fread(cur, sizeof(element_of_pattern), 1, input);
       
        if (prev != NULL)
            prev->next = cur;
        
        prev = cur;
    }
    cur->next = NULL;
    pat->first = first;
    
    // Odczyt łańcuchów znaków dla elementów typu STRING.
    for (cur = first; cur != NULL; cur = cur->next) {
        if (cur->type == STRING) {
            // Odczyt długości stringa.
            fread(&len, sizeof(len), 1, input);
            // Odczyt stringa.
            cur->data._string = malloc(len*sizeof(char));
            fread(cur->data._string, sizeof(char), len, input);            
        }
    }
    
    fclose(input);
    
    return pat;
}


void write_pattern(const char * path,const  pattern* p)
{
    int count, len;
    element_of_pattern *first, *cur;
    FILE *output = fopen(path, "wb");
    
    if (output == NULL) {
        printf("Nie udalo sie utworzyc pliku do zapisu wzorca krotki (%s).", path);
        return;
    }
    
    // Zapisanie PIDu procesu do pliku.
    pid_t pid = getpid();
    fwrite(&pid, sizeof(pid_t), 1, output);
    
    // Zliczenie elementów wzorca.
    for (count=0, cur=first=p->first; cur != NULL; cur = cur->next)
        count++;
    
    // Zapisanie liczby elementów do pliku.
    fwrite(&count, sizeof(count), 1, output);
    
    // Zapisanie struktury wzorca do pliku.
    fwrite(p, sizeof(pattern), 1, output);
    
    // Zapisanie struktur elementów wzorca krotki.
    for (cur = first; cur != NULL; cur = cur->next) 
        fwrite(cur, sizeof(element_of_pattern), 1, output);
    
    // Zapisanie łańcuchów znaków dla elementów typu STRING.
    for (cur = first; cur != NULL; cur = cur->next) {
        if (cur->type == STRING) {
            len = strlen(cur->data._string) + 1; // ze znakiem '\0'.
            // Zapis rozmiaru stringa
            fwrite(&len, sizeof(len), 1, output);
            // Zapis stringa
            fwrite(cur->data._string, sizeof(char), len, output);
        }   
    }
    
    fclose(output);
}


tuple* read_tuple(const char * path)
{
    int count, i, len;
    tuple *tup;
    element_of_tuple *first, *cur = NULL, *prev = NULL;
    FILE *input = fopen(path, "rb");
    
    if (input == NULL) {
        printf("Nie udalo sie otworzyc pliku krotki do odczytu (%s).", path);
        return NULL;
    }
    
    // Odczytanie liczby elementów krotki.
    fread(&count, sizeof(count), 1, input);
    
    // Alokacja pamięci dla krotki.
    tup = malloc(sizeof(tuple));

    if (count == 0) {
        tup->first = NULL;
        return tup;
    }
    
    first = malloc(sizeof(element_of_tuple));
    
    // Odczyt struktur krotki.
    for (i = 0; i < count; i++) {
        if (prev != NULL)
            cur = malloc(sizeof(element_of_tuple));
        else
            cur = first;
        
        fread(cur, sizeof(element_of_tuple), 1, input);
        
        if (prev != NULL)
            prev->next = cur;
        
        prev = cur;
    }
    cur->next = NULL;
    tup->first = first;
    
    // Odczyt łańcuchów znaków dla elementów typu STRING.
    for (cur = first; cur != NULL; cur = cur->next) {
        if (cur->type == STRING) {
            // Odczyt długości stringa.
            fread(&len, sizeof(len), 1, input);
            // Odczyt stringa.
            cur->data._string = malloc(len*sizeof(char));
            fread(cur->data._string, sizeof(char), len, input);            
        }
    }
    
    fclose(input);
    
    return tup;
}


void write_tuple(const char * path, const tuple* t)
{
    int count, len;
    element_of_tuple *first, *cur;
    FILE *output = fopen(path, "wb");
    
    if (output == NULL) {
        printf("Nie udalo sie utworzyc pliku do zapisu krotki (%s).", path);
        return;
    }
    
    // Zliczenie elementów krotki.
    for (count=0, cur=first=t->first; cur != NULL; cur = cur->next)
        count++;
   
    // Zapisanie liczby elementów do pliku.
    fwrite(&count, sizeof(count), 1, output);
    
    // Zapisanie struktur elementów krotki.
    for (cur = first; cur != NULL; cur = cur->next)
        fwrite(cur, sizeof(element_of_tuple), 1, output);
    
    // Zapisanie łańcuchów znaków dla elementów typu STRING.
    for (cur = first; cur != NULL; cur = cur->next) {
        if (cur->type == STRING) {
            len = strlen(cur->data._string) + 1; // ze znakiem '\0'.
            // Zapis rozmiaru stringa
            fwrite(&len, sizeof(len), 1, output);
            // Zapis stringa
            fwrite(cur->data._string, sizeof(char), len, output);
        }   
    }
    
    fclose(output);
}
